﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.Security.Permissions;

namespace Rsdn.Humor.Collector
{
  using InfoTop10Type = SortedList<long, ResId>;
  using InfoStatType = Dictionary<ResId, Statistics.StatInfo>;
  using UserStatType = Dictionary<ResId, Statistics.StatUser>;


  [Serializable]
  class Statistics : ISerializable
  {
    [Serializable]
    public struct StatInfo
    {
      public int SmilesCount; //число смайлов
      public int Dissent;     //несогласия (-)
      public int Assent;      //согласия (+)
      public int Rate;        //суммарный рейтинг
      public int Raters;      //всего оценщиков

      public long HumorouslyRate
      {
        get
        {
          return 1000000L * SmilesCount + 100 * Rate + Assent - Dissent;
        }
      }
      
      public static StatInfo operator +(StatInfo s1, StatInfo s2)
      {
        s1.Assent += s2.Assent;
        s1.Dissent += s2.Dissent;
        s1.Rate += s2.Rate;
        s1.Raters += s2.Raters;
        s1.SmilesCount += s2.SmilesCount;
        return s1;
      }
    }

    [Serializable]
    public struct StatUser
    {
      Dictionary<ResId, StatInfo> Rate;        //рейтинг по сообщениям (id сообщения, оценка)
    }

    private InfoTop10Type _InfoTop10 = new InfoTop10Type(20);
    private InfoStatType _Info = new InfoStatType();
    private UserStatType _Users = new UserStatType();

    public bool HasStatInfo(ref ResId id)
    {
      return _Info.ContainsKey(id);
    }

    public void SetStatInfo(ref ResId id, ref StatInfo info)
    {
      lock (_Info)
      {
        StatInfo existing_info;
        if (!_Info.TryGetValue(id, out existing_info))
          _Info.Add(id, info);
        else
        {
          info += existing_info;
          _Info[id] = info;
        }
        
        var r = info.HumorouslyRate;
        if(!_InfoTop10.ContainsKey(r) && _InfoTop10.FirstOrDefault().Key < r)
        {
          var index = _InfoTop10.Values.IndexOf(id);
          if (index != -1)
            _InfoTop10.RemoveAt(index);

          _InfoTop10.Add(r, id);
          while(_InfoTop10.Count > 10)
            _InfoTop10.RemoveAt(0);
        }
      }
    }

    public ResId[] GetTop10Info()
    {
      lock(_Info)
        return _InfoTop10.Values.ToArray();
    }

    private Statistics(SerializationInfo info, StreamingContext context)
    {
      _Info = (InfoStatType)info.GetValue("_Info", typeof(InfoStatType));
      _Users = (UserStatType)info.GetValue("_Users", typeof(UserStatType));
      _InfoTop10 = (InfoTop10Type)info.GetValue("_InfoTop10", typeof(InfoTop10Type));
    }

    public Statistics()
    {
    }

    [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
      lock(_Info)
      lock(_Users)  
      {
        info.AddValue("_Info", _Info, typeof(InfoStatType));
        info.AddValue("_Users", _Users, typeof(UserStatType));
        info.AddValue("_InfoTop10", _InfoTop10, typeof(InfoTop10Type));
      }
    }
  }
}
